package com.iplant.wms.serviceImpl.dao.asn;

import com.iplant.base.po.OutResult;
import com.iplant.base.po.Pagination;
import com.iplant.base.po.enums.ExceptionTypes;
import com.iplant.base.po.excel.ExcelData;
import com.iplant.base.po.excel.ExcelLineData;
import com.iplant.base.po.excel.ExcelSheetData;
import com.iplant.base.utils.annotation.dao.DBBaseDAO;
import com.iplant.base.utils.cache.CacheUtils;
import com.iplant.base.utils.general.StringUtils;
import com.iplant.base.utils.sql.BaseDAO;
import com.iplant.basic.service.po.bms.BMSEmployee;
import com.iplant.basic.service.po.crm.CRMCustomer;
import com.iplant.wms.service.basicenum.asn.WMSReceiveStatus;
import com.iplant.wms.service.basicenum.asn.WMSReceiveType;
import com.iplant.wms.service.po.asn.WMSArrivalNotice;
import com.iplant.wms.service.po.asn.WMSArrivalNoticeItem;
import com.iplant.wms.service.po.bill.WMSBillType;
import com.iplant.wms.service.po.mfs.WMSStore;
import com.iplant.wms.service.po.wpo.WMSPurchaseOrder;
import com.iplant.wms.service.po.wpo.WMSPurchaseOrderItem;
import com.iplant.wms.serviceImpl.dao.bill.WMSBillTypeDAO;
import com.iplant.wms.serviceImpl.dao.wpo.WMSPurchaseOrderItemDAO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author xiuto
 */
@Slf4j
@DBBaseDAO(WMSArrivalNotice.class )
public class WMSArrivalNoticeDAO extends BaseDAO implements DisposableBean {



    private static WMSArrivalNoticeDAO Instance = null;


    private boolean IsStart = true;


    private WMSArrivalNoticeDAO() {
        super("");
        this.Init();
        new Thread(() -> {
            this.WMS_CreateAsnMsgThread();
        }).start();
    }

    public static WMSArrivalNoticeDAO getInstance() {
        if (Instance == null) {
            synchronized (WMSArrivalNoticeDAO.class) {
                if (Instance == null) {
                    Instance = new WMSArrivalNoticeDAO();
                }
            }
        }
        return Instance;
    }


    /**
     * 由到货单及其子项，创建收货单及其子项
     *
     * @param wLoginUser        用户
     * @param wPurchaseOrder 到货单（包括子项）
     * @param wErrorCode        错误代码
     * @return 收货单对象（包括子项）
     */
    public WMSArrivalNotice WMS_CreateFromPurchaseOrder(BMSEmployee wLoginUser, WMSPurchaseOrder wPurchaseOrder, OutResult<Integer> wErrorCode) {
        WMSArrivalNotice wArrivalNotice = new WMSArrivalNotice();
        int wParentID = 0; // 生成的主单据ID，若子单据生成过程中异常，可回滚；
        OutResult<Integer> wErrorCodeSub = new OutResult<>(0);
        // 处理子项时的ErrorCode，防止自带ErrorCode被回滚函数给复位成0，无法返回给前端的错误情况；
        try {

            if (wPurchaseOrder == null || wPurchaseOrder.ID <= 0 || StringUtils.isEmpty(wPurchaseOrder.Code)) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wArrivalNotice;
            }
            wPurchaseOrder.ItemList = WMSPurchaseOrderItemDAO.getInstance().WMS_QueryPurchaseOrderItemListByPurchaseOrder(wLoginUser,
                    wPurchaseOrder.ID,"", Pagination.getMaxSize(WMSPurchaseOrderItem.class), wErrorCode);
            if (wErrorCode.Result != 0) {
                return wArrivalNotice;
            }

            if (wPurchaseOrder.ItemList == null || wPurchaseOrder.ItemList.size() == 0) {
                log.info("WMS_CreateFromPurchaseOrder", "有效的物料清单为空。");
                wErrorCode.Result = ExceptionTypes.Parameter.getValue();
                return wArrivalNotice;
            }
            // 主单据
            wArrivalNotice.Name = wPurchaseOrder.Name;
            wArrivalNotice.Active = wPurchaseOrder.Active;
            wArrivalNotice.FactoryID = wPurchaseOrder.FactoryID;
            wArrivalNotice.FactoryCode = wPurchaseOrder.FactoryCode;
            wArrivalNotice.FactoryName = wPurchaseOrder.FactoryName;
            wArrivalNotice.PurchaseOrderID = wPurchaseOrder.ID;
            wArrivalNotice.PurchaseOrderCode = wPurchaseOrder.Code;
            wArrivalNotice.TypeID = WMSReceiveType.Purchase.getValue();
            wArrivalNotice.StoreID = wPurchaseOrder.StoreID;
            wArrivalNotice.CustomerID = wPurchaseOrder.CustomerID;
            wArrivalNotice.SupplierID = wPurchaseOrder.SupplierID;
            wArrivalNotice.SupplierAddress = wPurchaseOrder.SupplierAddress;
            wArrivalNotice.SupplierContact = wPurchaseOrder.SupplierContact;
            wArrivalNotice.SupplierTel = wPurchaseOrder.SupplierTel;
            wArrivalNotice.ProjectNo = wPurchaseOrder.ProjectNo;
            wArrivalNotice.ProjectName = wPurchaseOrder.ProjectName;

            wArrivalNotice.Status = WMSReceiveStatus.GoodsToBeReceived.getValue();
            wArrivalNotice.Description=wPurchaseOrder.Description;
            wArrivalNotice.setUserInfo(wLoginUser);
            // 保存主单据以获得ID给子项
            this.UpdatePo(wLoginUser, wArrivalNotice, wErrorCode);
            if (wErrorCode.Result != 0) {
                return wArrivalNotice;
            }
            if (wArrivalNotice == null || wArrivalNotice.ID <= 0) {
                return wArrivalNotice;
            }


            for (WMSPurchaseOrderItem wPurchaseOrderItem : wPurchaseOrder.ItemList) {
                WMSArrivalNoticeItem wArrivalNoticeItem = new WMSArrivalNoticeItem();
                wArrivalNoticeItem.FactoryID = wPurchaseOrderItem.FactoryID;
                wArrivalNoticeItem.ArrivalNoticeID = wArrivalNotice.ID;
                wArrivalNoticeItem.ArrivalNoticeCode = wArrivalNotice.Code;
                wArrivalNoticeItem.CustomerID = wPurchaseOrderItem.CustomerID;
                wArrivalNoticeItem.CustomerCode = wPurchaseOrderItem.CustomerCode;
                wArrivalNoticeItem.CustomerName = wPurchaseOrderItem.CustomerName;
                wArrivalNoticeItem.SupplierID = wPurchaseOrderItem.SupplierID;
                wArrivalNoticeItem.SupplierCode = wPurchaseOrderItem.SupplierCode;
                wArrivalNoticeItem.SupplierName = wPurchaseOrderItem.SupplierName;
                wArrivalNoticeItem.PurchaseOrderItemID = wPurchaseOrderItem.ID;
                wArrivalNoticeItem.PurchaseOrderItemCode = wPurchaseOrderItem.Code;
                wArrivalNoticeItem.PurchaseOrderID = wPurchaseOrderItem.PurchaseOrderID;
                wArrivalNoticeItem.PurchaseOrderCode = wPurchaseOrderItem.PurchaseOrderCode;
                wArrivalNoticeItem.MaterialID = wPurchaseOrderItem.MaterialID;
                wArrivalNoticeItem.MaterialCode = wPurchaseOrderItem.MaterialCode;
                wArrivalNoticeItem.MaterialName = wPurchaseOrderItem.MaterialName;
                wArrivalNoticeItem.PackageRuleID = wPurchaseOrderItem.PackageRuleID;
                wArrivalNoticeItem.PackageRuleCode = wPurchaseOrderItem.PackageRuleCode;
                wArrivalNoticeItem.PackageRuleName = wPurchaseOrderItem.PackageRuleName;
                wArrivalNoticeItem.MaterialNumber = wPurchaseOrderItem.MaterialNumber;
                wArrivalNoticeItem.ReceivedMaterialNumber = 0.0; // 待用户填
                wArrivalNoticeItem.ReceiveUnit = wPurchaseOrderItem.ReceiveUnit;
                wArrivalNoticeItem.ReceiveUnitText = wPurchaseOrderItem.ReceiveUnitText;
                wArrivalNoticeItem.TotalVolume = wPurchaseOrderItem.TotalVolume;
                wArrivalNoticeItem.TotalGrossWeight = wPurchaseOrderItem.TotalGrossWeight;
                wArrivalNoticeItem.TotalNetWeight = wPurchaseOrderItem.TotalNetWeight;
                wArrivalNoticeItem.TotalPrice = wPurchaseOrderItem.TotalPrice;
                wArrivalNoticeItem.Description=wPurchaseOrderItem.Description;
                wArrivalNoticeItem.StoreID = wPurchaseOrderItem.StoreID;
                wArrivalNoticeItem.StoreName = wPurchaseOrderItem.StoreName;
                wArrivalNoticeItem.StoreCode = wPurchaseOrderItem.StoreCode;

                wArrivalNoticeItem.ProjectNo = wPurchaseOrderItem.ProjectNo;
                wArrivalNoticeItem.ProjectName = wPurchaseOrderItem.ProjectName;

                wArrivalNoticeItem.setUserInfo(wLoginUser);
                wArrivalNotice.ItemList.add(wArrivalNoticeItem);
            }
            // 之所以没有用BasePO的UpdatePo逐个保存，是此过程作为一个整体执行，避免中途报错无法回滚，因此带来的问题是无法自动生成Code；
            this.UpdatePoList(wLoginUser, wArrivalNotice.ItemList, wErrorCode);

        } catch (Exception ex) {
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            log.error("WMS_CreateFromArrival", ex);
        }
        // 如果出错了，且主单据插入成功，则删掉主单据
        if (wErrorCodeSub.Result > 0 && wParentID > 0) {
            int wDeleteResult = DeletePO(wLoginUser, wArrivalNotice, wErrorCode);
            wErrorCode.set(wErrorCodeSub.Result);
        }

        return wArrivalNotice;
    }



    /**
     * 删除集合
     *
     * @param wList
     */
    public void WMS_DeleteArrivalNoticeList(
            BMSEmployee wLoginUser, List<WMSArrivalNotice> wList, OutResult<Integer> wErrorCode) {
        try {
            if (wList == null || wList.size() == 0) {
                return;
            }
            this.DeletePOList(wLoginUser, wList, wErrorCode);

            if (wErrorCode.Result != 0) {
                return;
            }
            List<Integer> wIDList = wList.stream().filter(p -> p.ID > 0).map(p -> p.ID).distinct().collect(Collectors.toList());
            WMSArrivalVehicleDAO.getInstance().WMS_DeleteArrivalVehicleList(
                    wLoginUser,wIDList, wErrorCode);

            if (wErrorCode.Result != 0) {
                return;
            }
            WMSReceiveBillDAO.getInstance().WMS_DeleteReceiveBillList(wLoginUser,wIDList
                    , wErrorCode);

        } catch (Exception ex) {
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            log.error(ex.toString());
        }
    }


    public void WMS_DeleteArrivalNotice(
            BMSEmployee wLoginUser, WMSArrivalNotice wWMSArrivalNotice, OutResult<Integer> wErrorCode) {
        try {
            if (wWMSArrivalNotice == null || wWMSArrivalNotice.ID < 0) {
                return;
            }
            this.DeletePO(wLoginUser, wWMSArrivalNotice, wErrorCode);

            if (wErrorCode.Result != 0) {
                return;
            }
            WMSArrivalVehicleDAO.getInstance().WMS_DeleteArrivalVehicleList(wLoginUser,wWMSArrivalNotice.ID, wErrorCode);

            if (wErrorCode.Result != 0) {
                return;
            }
            WMSReceiveBillDAO.getInstance().WMS_DeleteReceiveBillList(wLoginUser,wWMSArrivalNotice.ID
                    , wErrorCode);

        } catch (Exception ex) {
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            log.error(ex.toString());
        }
    }



    /**
     * Excel数据解析
     */
    public List<WMSArrivalNotice> GetWMSArrivalNoticeList(
            BMSEmployee wLoginUser, ExcelData wExcelData, OutResult<Integer> wErrorCode) {
        List<WMSArrivalNotice> wResult = new ArrayList<WMSArrivalNotice>();
        wErrorCode.set(0);
        try {
            if (wExcelData.sheetData == null || wExcelData.sheetData.size() == 0) {
                return wResult;
            }

            ExcelSheetData wSheetData = wExcelData.sheetData.get(0);
            if (wSheetData.lineData == null || wSheetData.lineData.size() == 0) {
                return wResult;
            }


            int wRow = 0;

            List<WMSBillType> wOrderTypeList = WMSBillTypeDAO.getInstance().WMS_QueryBillTypeList(wLoginUser, 1,
                    1, Pagination.getMaxSize(), wErrorCode);
            if (wErrorCode.Result != 0) {
                return wResult;
            }

            List<CRMCustomer> wCustomerList = CacheUtils.GetCacheTList(CRMCustomer.class);

            List<WMSStore> wStoreList = CacheUtils.GetCacheTList(WMSStore.class);


            Map<String, CRMCustomer> wCRMCustomerMap = wCustomerList.stream().collect(
                    Collectors.toMap(p -> p.Code, p -> p));
            Map<String, WMSStore> wWMSStoreMap = wStoreList.stream().collect(Collectors.toMap(p -> p.Code, p -> p));
            Map<String, WMSBillType> wWMSBillTypeMap = wOrderTypeList.stream().collect(
                    Collectors.toMap(p -> p.Code, p -> p));


            for (ExcelLineData wExcelLineData : wSheetData.lineData) {
                if (wRow == 0) {
                    wRow++;
                    continue;
                }

                String wPONo = wExcelLineData.colData.get(0);
                String wType = wExcelLineData.colData.get(1);
                String wCustomer = wExcelLineData.colData.get(2);
                String wExTime1 = wExcelLineData.colData.get(3);
                String wExTime2 = wExcelLineData.colData.get(4);
                String wWBSNo = wExcelLineData.colData.get(5);
                String wSuperNo = wExcelLineData.colData.get(6);
                String wSuperName = wExcelLineData.colData.get(7);
                String wSuperAddress = wExcelLineData.colData.get(8);
                String wContactor = wExcelLineData.colData.get(9);
                String wPhone = wExcelLineData.colData.get(10);
                String wStore = wExcelLineData.colData.get(11);

                WMSArrivalNotice wWMSArrivalNotice = new WMSArrivalNotice();
                wWMSArrivalNotice.ID = 0;
                wWMSArrivalNotice.Code = wPONo;
                wWMSArrivalNotice.Active = 1;
                wWMSArrivalNotice.CustomerCode = wCustomer;
                if (wCRMCustomerMap.containsKey(wWMSArrivalNotice.CustomerCode)) {
                    wWMSArrivalNotice.CustomerID = wCRMCustomerMap.get(wWMSArrivalNotice.CustomerCode).ID;
                    wWMSArrivalNotice.CustomerName = wCRMCustomerMap.get(wWMSArrivalNotice.CustomerCode).Name;
                }
                if (wWMSBillTypeMap.containsKey(wWMSArrivalNotice.TypeCode)) {
                    wWMSArrivalNotice.TypeID = wWMSBillTypeMap.get(wWMSArrivalNotice.TypeCode).ID;
                    wWMSArrivalNotice.TypeName = wWMSBillTypeMap.get(wWMSArrivalNotice.TypeCode).Name;
                }
                //
                wWMSArrivalNotice.ArriveStartTime = StringUtils.parseCalendar(wExTime1);
                wWMSArrivalNotice.ArriveEndTime = StringUtils.parseCalendar(wExTime2);
                wWMSArrivalNotice.POReference1 = wWBSNo;
                wWMSArrivalNotice.SupplierCode = wSuperNo;
                wWMSArrivalNotice.SupplierName = wSuperName;
                if (wCRMCustomerMap.containsKey(wWMSArrivalNotice.SupplierCode)) {
                    wWMSArrivalNotice.SupplierID = wCRMCustomerMap.get(wWMSArrivalNotice.SupplierCode).ID;
                    if (StringUtils.isEmpty(wWMSArrivalNotice.SupplierName)) {
                        wWMSArrivalNotice.SupplierName = wCRMCustomerMap.get(wWMSArrivalNotice.SupplierCode).Name;
                    }
                }
                wWMSArrivalNotice.SupplierAddress = wSuperAddress;
                wWMSArrivalNotice.SupplierContact = wContactor;
                wWMSArrivalNotice.SupplierTel = wPhone;
                wWMSArrivalNotice.StoreCode = wStore;
                if (wWMSStoreMap.containsKey(wWMSArrivalNotice.StoreCode)) {
                    wWMSArrivalNotice.StoreID = wWMSStoreMap.get(wWMSArrivalNotice.StoreCode).ID;
                    wWMSArrivalNotice.StoreName = wWMSStoreMap.get(wWMSArrivalNotice.StoreCode).Name;

                }
                wResult.add(wWMSArrivalNotice);
            }
        } catch (Exception ex) {
            log.error(ex.toString());
        }
        return wResult;
    }


    private void WMS_CreateAsnMsgThread() {
        try {

            while (IsStart) {
                try {

                    this.WMS_CreateAsnMsg(BMSEmployee.SysAdmin);
                } catch (Exception ex) {
                    log.error("WMS_CreateAsnMsgThread While ", ex);
                }
            }
        } catch (Exception ex) {
            log.error("WMS_CreateAsnMsgThread ", ex);
        }
    }

    private void WMS_CreateAsnMsg(BMSEmployee wLoginUser) {
        try {
            //创建任务消息给收货员


        } catch (Exception ex) {
            log.error("WMS_CreateAsnMsg ", ex);
        }
    }

    @Override
    public void destroy() throws Exception {
        IsStart = false;
    }
}
